#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <sys/select.h>
#include <sys/poll.h>
#include "Log.hpp"
#include "Socket.hpp"

Log lg;
using namespace Network;
using namespace std;

const static int gdefaultport = 8888;
const static int gbacklog = 8;

//const static int num = sizeof(fd_set) * 8;

const int gnum=1024;
class PollServer
{
private:
    void HandlerEvent()
    {
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            // 合法的sockfd
            // 读事件分为两类的，一类是新连接到来，一类是新数据到来
            int fd = _rfds[i].fd;
            short revents=_rfds[i].revents;
            if (revents & POLLIN)
            {
                // 读事件就绪
                if (fd == _listensock->GetSockfd())
                {
                    //新连接到来了
                    lg.LogMessage(Info, "get a new link\n");
                    // 获取连接
                    string clientip;
                    uint16_t clientport;
                    // 不会阻塞！！因为poll已经检测到了listensock已经就绪了
                    int sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (sock==-1)
                    {
                        lg.LogMessage(Error, "accept error\n");
                        continue;
                    }
                    lg.LogMessage(Info, "get a client, client info is# %s:%d,fd:%d\n", clientip.c_str(), clientport, sock);

                    // 这里已经获取连接成功了，接下来怎么办呢？
                    // read？write？绝对不能！！！read底层数据是否就绪是不确定的！谁最清楚fd上面是否有读取事件呢？poll！
                    // 新连接fd到来的时候，要把新的fd，想办法交给poll来管理——只需要将新的fd添加到_rfds_arry中即可
                    int pos = 0;
                    for (; pos < _num; pos++)
                    {
                        if (_rfds[pos].fd == -1)
                        {
                            _rfds[pos].fd = sock;
                            _rfds[pos].events=POLLIN;
                            lg.LogMessage(Info, "get a new link,fd is %d\n", sock);
                            break;
                        }
                    }
                    if (pos == _num)
                    {
                        //1.扩容 2.关闭
                        close(sock);
                        lg.LogMessage(Warning, "server is full\n");
                    }
                }
                else
                {
                    // 普通的读事件就绪了
                    char buffer[1024];
                    ssize_t n=recv(fd,buffer,sizeof(buffer),0);
                    if (n>0)
                    {
                        buffer[n]=0;
                        lg.LogMessage(Info, "client say# %s\n", buffer);
                        string message="你好呀，少年";
                        message+=buffer;
                        send(fd,message.c_str(),message.size(),0);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit,mybe close or error,close fd: %d\n",fd);
                        close(fd);
                        //取消poll的关心
                        _rfds[i].fd=-1;
                        _rfds[i].events=0;
                        _rfds[i].revents=0;
                    }
                }
            }
        }
    }

public:
    PollServer(int port = gdefaultport) : _port(port), _listensock(new TcpSocket()), _isrunning(false),_num(gnum)
    {
    }
    void InitServer()
    {
        _listensock->BuildlistenSocketMethod(_port, gbacklog);
       _rfds=new struct pollfd[_num];
       for(int i=0;i<_num;i++)
       {
            _rfds[i].fd=-1;
            _rfds[i].events=0;
            _rfds[i].revents=0;
       }
       //最开始的时候，只有一个文件描述符，Listensock
       _rfds[0].fd=_listensock->GetSockfd();
       _rfds[0].events|=POLLIN;//新连接到来，就属于POLLIN事件
    }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 定义时间
            int timeout=1000;
            //struct timeval timeout = {0, 0};
            PrintDebug();
            int n = poll(_rfds,_num,timeout);
            switch (n)
            {
            case 0:
                lg.LogMessage(Info, "poll timeout....\n");
                break;
            case -1:
                lg.LogMessage(Error, "poll error!!!\n");
                break;
            default:
                // 正常的就绪fd
                lg.LogMessage(Info, "poll success,begin event handle\n");
                HandlerEvent();
                break;
            }
        }
        _isrunning = false;
    }
    void Stop()
    {
        _isrunning = false;
    }

    void PrintDebug()
    {
        std::cout << "current select rfds list is : ";
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            else
                std::cout << _rfds[i].fd << " ";
        }
        std::cout << std::endl;
    }

    ~PollServer()
    {
        delete []_rfds;
    }

private:
    unique_ptr<Socket> _listensock;
    int _port;
    bool _isrunning;
    struct pollfd* _rfds;
    int _num;
};

